import glgui2
import pyglet
from pyglet.gl import *
from math import *

def getAngle(x,y):
  if (x,y)==(1,1):
    return 0
  if (x,y)==(1,0):
    return 60
  if (x,y)==(0,-1):
    return 135
  if (x,y)==(-1,-1):
    return 180
  if (x,y)==(-1,0):
    return 225
  if (x,y)==(0,1):
    return 315
  return 0
  
class HexfieldPath: 
  def __init__(self,hexfield,width = 2.0,style = None,color = (255,255,255)):
    self.hexfield = hexfield
    self.line = pyglet.graphics.vertex_list(2, 'v2f', 'c3B')
    self.width = width
    self.style = style
    self.color = color
    
  def set_points(self,points):
    if points is None: return
    if len(points) < 2: return
    self.points = points
    tmp = []
    count = (len(points) - 1)
    self.line.resize(count)
    self.line.colors = (self.color*count)
    for va,vb in zip(self.points[:-1],self.points[1:]):
      x1,y1 = self.hexfield.to_screen(va[0],va[1])
      x2,y2 = self.hexfield.to_screen(vb[0],vb[1])
      tmp+=(x1+16,y1+14)
      tmp+=(x2+16,y2+14)
    self.line.vertices = tmp
  
  def draw(self):
    glEnable(GL_LINE_STIPPLE)
    glLineStipple(1, GLushort(int(0xEEEE))); 
    glLineWidth(4)
    self.line.draw(GL_LINES)
    glDisable(GL_LINE_STIPPLE)

class HexfieldPathPack:
  def __init__(self,hexfield):
    self.paths = hexfield.HexfieldPathPack(hexfield)
  def add_path(self,path):
    self.paths.add_path(path)
  def remove_path(self,path):
    self.paths.remove_path(path)
    
class HexfieldMarkers:
  def __init__(self,hexfield):
    self.hexfield = hexfield
    self.batch = pyglet.graphics.Batch()
    self.markers ={}
    
    
  def get_markers(self,x,y):
    x,y = self.hexfield.tile_pos(x,y)
    return self.get_marker(x,y)
    
  def get_marker(self,x,y):
    if x*self.hexfield.tile_count[1]+y in self.markers:
      return self.markers[x*self.hexfield.tile_count[1]+y]
    self.markers[x*self.hexfield.tile_count[1]+y] = []
    return self.markers[x*self.hexfield.tile_count[1]+y]
    
  def swap_markers(self,marker_a,marker_b):
    marker_a.image,marker_b.image = marker_b.image,marker_a.image
    marker_a.color,marker_b.color = marker_b.color ,marker_a.color
    marker_a.user_data,marker_b.user_data = marker_b.user_data,marker_a.user_data
    #marker_a.user_data,marker_b.user_data = marker_b.image,marker_a.user_data
    
  def rotate_markers(self,x,y):
    mks = self.get_marker(x,y)
    if len(mks)<2:
      return
    self.swap_markers(mks[-1], mks[0])
    for mark,nextmark in zip(mks,mks[1:-1]):
       self.swap_markers(mark,nextmark)
  
  def get_top_marker(self,x,y):
    x,y = self.hexfield.tile_pos(x,y)
    if len(self.get_marker(x,y))>0:
      return self.get_marker(x,y)[-1]
    return None
  
  def add(self,marker,x,y,user_data = None,convert = True):
    if convert:
      pos = self.hexfield.to_screen(x,y)
    else:
      pass
      
    marker.user_data = user_data
    marker.x = pos[0]
    marker.y = pos[1] + len(self.get_marker(x,y))*2
    self.get_marker(x,y).append(marker)
    marker.scale = (32.0/marker.image.width),(32.0/marker.image.height) 
    marker.batch = self.batch
    return marker
    
  def remove_marker(self,marker):
    for mark in self.markers:
      if marker in self.markers[mark]:
        self.markers[mark].remove(marker)
    marker.delete()
    
  def clear(self):
    for markers in self.markers:
      for marker in self.markers[markers]: 
        marker.delete()
    self.markers = {}
  
class Hexfield(glgui2.Widget):
  def __init__(self,name,tiles,tile_type_count,size):
    glgui2.Widget.__init__(self)
    pyglet.clock.schedule_interval(self.update, 1.0/150.0) 
    self.hex_image = pyglet.image.load(tiles)
    self.background = pyglet.sprite.Sprite(pyglet.image.load('graphics/test.png'), 0, 0,  blend_src=GL_SRC_ALPHA, blend_dest=GL_ONE_MINUS_SRC_ALPHA)
    self.background.rotation = 0
    self.texture_grid = pyglet.image.ImageGrid(self.hex_image,1,tile_type_count)
    self.batch = pyglet.graphics.Batch()
    self.tile_count = size
    self.codes = [1]*size[0]*size[1]
    self.hexes = []
    self.tile_size = self.hex_image.width/tile_type_count,self.hex_image.height
    self.view_size = (self.tile_count[0]+self.tile_count[1])*self.tile_size[1]/2,(self.tile_count[0]+self.tile_count[1])*self.tile_size[1]
    self.size = 1024,768
    self.pos = [-742.0,0.0]
    self.scale = [1.0,1.0]
    self.tmp_pos = [100,100]
    self.update_rect()
    self.markers = []
    self.sprites = []
  def add_markers(self,markers):
    self.markers.append(markers)
  
  
  def subscribe_to(self):
    glgui2.common_signals.connect_to_channel('events/mouse/mouse_motion',self.mouse_move)
    glgui2.common_signals.connect_to_channel('events/mouse/mouse_press',self.mouse_press)
    glgui2.common_signals.connect_to_channel('events/mouse/mouse_scroll',self.mouse_scroll)
    
    glgui2.common_signals.connect_to_channel('events/mouse/mouse_drag',self.mouse_drag)
  
  def mouse_scroll(self,x,y,dx,dy):
    
    if dy>0:
        self.rescale(1.1)
        
    if dy<0:
        self.rescale(1/1.1)
      
  def mouse_drag(self,x,y,dx,dy,buttons,mod):
    if buttons  == (pyglet.window.mouse.LEFT + pyglet.window.mouse.RIGHT):
      self.scroll(-dx/self.scale[0],-dy/self.scale[1])
      
  def block(self):
    glgui2.common_signals.set_block('events/mouse/mouse_motion',self.mouse_move,True)
    glgui2.common_signals.set_block('events/mouse/mouse_press',self.mouse_move,True)
    glgui2.common_signals.set_block('events/mouse/mouse_scroll',self.mouse_move,True)
    glgui2.common_signals.set_block('events/mouse/mouse_drag',self.mouse_drag,True)
    
  def unblock(self):
    glgui2.common_signals.set_block('events/mouse/mouse_motion',self.mouse_move,False)
    glgui2.common_signals.set_block('events/mouse/mouse_press',self.mouse_move,False)
    glgui2.common_signals.set_block('events/mouse/mouse_scroll',self.mouse_move,False)
    
    glgui2.common_signals.set_block('events/mouse/mouse_drag',self.mouse_drag,True)
    
  def mouse_press(self,x,y,button,mod):
    tmp = self.tile_pos(x,y)
    
  def mouse_move(self,x,y,dx,dy):
    self.tmp_pos = [x,y]
  
  def hit_test(self,x,y):
    x,y = self.tile_pos(x,y)
    if x < 0 or y <0 or x >= self.tile_count[0] or y >= self.tile_count[1]:
      return False
    return True
    
  def to_screen(self,x,y):
    #~ x+=9
    #~ y-=5
    retx = x - y
    rety = x + y
    retx,rety = int(retx*(self.tile_size[0]*3)/4), rety*self.tile_size[1]/2
    return (retx),(rety)
    
  def tile_pos(self,ax,ay):
    ay=ay
    ax/=(self.scale[0]) 
    ay/=(self.scale[1])
    ax = int(ax)
    ay = int(ay)
    posa = ax - self.tile_size[0]/2 ,ay
    posa = posa[0]+int(self.pos[0]) + self.tile_size[0]*3/8,posa[1]+int(self.pos[1])
    x,y = posa
    x,y = int(x*4/(self.tile_size[0]*3)), y*2/self.tile_size[1]
    nx = (x + y) / 2
    ny = (y - x) / 2
    return nx,ny
    
  def set_opacity(self,opacity):
    for sprite in self.hexes:
      sprite.opacity = opacity
    
  def scroll(self,x,y):
    x = float(x*self.scale[0])
    y = float(y*self.scale[1])
    
    #if self.pos[0]+x < -740 or self.pos[0]+x > -256: #or self.pos[1]+y > self.view_size[1]+min or self.pos[1]+y < min:
    #return
      
    self.pos = self.pos[0] + x, self.pos[1]+y
      
  def rescale(self,scl):
    self.scale[0]*=scl
    self.scale[1]*=scl
  
  def update(self,dt):
    
    #if self.hit_test(self.tmp_pos[0],self.tmp_pos[1]):
      if self.tmp_pos[0] < 10:
        self.scroll(-8,0)
      if self.tmp_pos[0] > 1000:
        self.scroll(8,0)
      if self.tmp_pos[1] < 10:
        self.scroll(0,-8)
      if self.tmp_pos[1] > 758:
        self.scroll(0,8)
  
  def draw(self):
      
    glPushMatrix()
    
    glScalef(self.scale[0],self.scale[1],0)
    glTranslatef(-self.pos[0],-self.pos[1],0)
    
    glPushMatrix()
    glScalef(self.background.image.width/float(self.view_size[0]+30),self.background.image.height/float(self.view_size[1]-170),1.0)
    self.background.draw()
    glPopMatrix()
    self.batch.draw()
    for marker in self.markers:
      if marker.__class__.__name__ in ('HexfieldPath','HefieldPathPack') :
        marker.draw()
      else:
        marker.batch.draw()
    glPopMatrix()
  
  def _set_code(self,x,y,value):
    #print x,y
    #~ if(x<0)or(x>self.tile_count[0])or(y>self.tile_count[1])or(y<0):
      #~ return
    self.codes[x*self.tile_count[1]+y] = value
    self.sprites[x*self.tile_count[1]+y].image = self.texture_grid[value]
    
  def _get_code(self,x,y):
    return self.codes[x*self.tile_count[1]+y]
  
  code = property(_get_code,_set_code)
  
  def build(self):
      self.sprites = []
      for x in range(self.tile_count[0]):
        for y in range(self.tile_count[1]):
            r = self.to_screen(x,y)
            sprite = pyglet.sprite.Sprite(self.texture_grid[self._get_code(x,y)], r[0], r[1],  blend_src=GL_SRC_ALPHA, blend_dest=GL_ONE_MINUS_SRC_ALPHA,batch=self.batch)
            self.sprites.append(sprite)
            sprite.transparency = 120
            self.hexes.append(sprite)
     
      self.background.x ,self.background.y = self.to_screen(1,0)
      self.background.rotation = -45
